package com.qf.ability.application;

import com.alibaba.csp.sentinel.cluster.ClusterStateManager;
import com.alibaba.csp.sentinel.cluster.flow.rule.ClusterFlowRuleManager;
import com.alibaba.csp.sentinel.cluster.server.ClusterTokenServer;
import com.alibaba.csp.sentinel.cluster.server.SentinelDefaultTokenServer;
import com.alibaba.csp.sentinel.cluster.server.config.ClusterServerConfigManager;
import com.alibaba.csp.sentinel.cluster.server.config.ServerTransportConfig;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import com.alibaba.csp.sentinel.property.SentinelProperty;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.qf.commons.sentinel.config.SentinelNacosConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Set;

@Component
public class ApplicationRunning  implements CommandLineRunner {

    @Value("${server.port}")
    private Integer port;

    @Autowired
    private SentinelNacosConfig sentinelNacosConfig;



    @Override
    public void run(String... args) throws Exception {
        //启动服务
        // 加载服务配置
        ClusterServerConfigManager.loadGlobalTransportConfig(new ServerTransportConfig()
                .setIdleSeconds(600)
                .setPort(port));
        //启动服务
        ClusterTokenServer tokenServer = new SentinelDefaultTokenServer();
        tokenServer.start();

        //切换服务器的身份 - 集群服务端
        ClusterStateManager.applyState(ClusterStateManager.CLUSTER_SERVER);

        //根据namespace 加载对应的集群限流规则 回调
        ClusterFlowRuleManager.setPropertySupplier(namespace -> {
            ReadableDataSource<String, List<FlowRule>> ds = new NacosDataSource<>(
                    sentinelNacosConfig.getHost(),
                    sentinelNacosConfig.getGroup(),
                    namespace + sentinelNacosConfig.getFlowPrefix(),
                    source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {}));
            SentinelProperty<List<FlowRule>> property = ds.getProperty();
            return property;
        });


        //namepace -> ["appa", "appb"]
        //配置动态的命名空间数据源 -- 必须放在最后
        ReadableDataSource<String, Set<String>> namespaceDs = new NacosDataSource<>(
                sentinelNacosConfig.getHost(),
                sentinelNacosConfig.getGroup(),
                sentinelNacosConfig.getNamespaces(),
                source -> JSON.parseObject(source, new TypeReference<Set<String>>() {}));
        //注册Sentinel集群流控服务端的namespace列表（每个namespace就代表一个微服务）
        ClusterServerConfigManager.registerNamespaceSetProperty(namespaceDs.getProperty());
    }
}
